/*
----------------------------------------------------------------------------------------------------
This source file is part of the Gamut Framework
Copyright (c) 2007 by Ryan Holcombe

This program is free software; you can redistribute it and/or modify it under the terms of the GNU
Lesser General Public License as published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
----------------------------------------------------------------------------------------------------
*/


#include "GamutLogger.h"
#include "GamutLogFile.h"
#include <stdarg.h>
#include <time.h>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <cassert>

namespace Gamut
{
	//! Declare Singleton
	template<> Logger* Singleton<Logger>::ms_Singleton = 0;

	// -------------------------------------------------------------------------------------------//
	Logger::Logger(LogLevel level)
	{
		setLogLevel(level);
	}
	
	// -------------------------------------------------------------------------------------------//
	Logger::Logger(const std::string& filename, LogLevel level)
	{
		setLogLevel(level);
		
		// create a file listener
		addListener(IListenerPtr(new Gamut::LogFile(filename)));
	}
	
	// -------------------------------------------------------------------------------------------//
	Logger::~Logger()
	{
		ListenerList::iterator iter;
		while ((iter = mListener.begin()) != mListener.end())
		{
			destroyListener(*iter);
		}

		mListener.clear();
	}
	
	// -------------------------------------------------------------------------------------------//
	void Logger::logEvent(const std::string& file, int line, LogLevel level, const std::string& msg)
	{
		std::string ll, s;
		std::stringstream logtime;
		time_t rawtime;
		struct tm *t;
		
		if (level <= mLogLevel)
		{
			// convert the log level to a string
			switch (level)
			{
				case 1: ll = "Exception"; break;
				case 2: ll = "Warning"; break;
				case 3: ll = "Normal"; break;
				case 4: ll = "Informational"; break;
			}
			
						
			// get the current time
			rawtime = time(NULL);
			t = localtime(&rawtime);
			logtime << std::setw(2) << std::setfill('0') << t->tm_min << ":"
					<< std::setw(2) << std::setfill('0') << t->tm_sec;
			
			// write an entry to each attached listener
			for (ListenerList::iterator iter = mListener.begin(); iter != mListener.end(); iter++)
			{
				(*iter)->writeEntry(msg, file, line, logtime.str(), ll);
			}
		}
	}
	
	// -------------------------------------------------------------------------------------------//
	void Logger::logEvent(const std::string& file, int line, LogLevel level, const char *msg, ...)
	{
		std::string s;
		char buf[1024];
		
		if (level <= mLogLevel)
		{
			// build the message
			va_list args;
			va_start(args, msg);
			vsnprintf(buf, sizeof(buf), msg, args);
			va_end(args);
			s = std::string(buf);

			
			Logger::logEvent(file, line, level, s);
		}
	}
	
	// -------------------------------------------------------------------------------------------//
	IListenerPtr Logger::addListener(IListenerPtr listener)
	{
		assert(listener);
			
		listener->onListenerAdd();
		mListener.push_back(listener);
		LOGF3("Log Listener (%p) added", listener.get());

		return listener;
	}
	
	// -------------------------------------------------------------------------------------------//
	void Logger::removeListener(IListenerPtr listener)
	{
		assert(listener);

		ListenerList::iterator iter = mListener.begin();
		while (*iter != listener)
		{
			if (iter == mListener.end())
			{
				LOGF2("Unable to find log listener (%p) in the list", listener.get());
				return;
			}

			iter++;
		}
		
		LOGF3("Log Listener (%p) removed", listener.get());
		mListener.erase(iter);
	}
	
	// -------------------------------------------------------------------------------------------//
	void Logger::destroyListener(IListenerPtr listener)
	{
		assert(listener);

		ListenerList::iterator iter = mListener.begin();
		while (*iter != listener)
		{
			if (iter == mListener.end())
			{
				LOGF2("Unable to find log listener (%p) in the list", listener.get());
				return;
			}

			iter++;
		}
		
		LOGF3("Log Listener (%p) destroyed", listener.get());
		listener->onListenerDestroy();

		mListener.erase(iter);
	}
}
